import moment from 'moment';
import * as tools from 'src-ssr/util/common';
import { Sequelize, Op } from 'sequelize';
import models from 'src-ssr/db/sequelize';

/**
 * 生成新编号，编号规格 固定词+可替换词+自动编号
 * prefix前缀字段值，固定词直接填写即可，可替换的关键词有如下：
 * {{date}} YYMMDD格式日期
 * {{longdate}} YYYYMMDD格式日期
 * {{tid}} 租户id
 * {{custom}} 自定义内容
 * 自动编码的升序由length这个字段指定
 * @param {string} code 自动编码表里的代码
 * @param {object} tid 租户id
 * @param {string} custom 用户自定义字符串
 * @param {number} digits 流水号长度
 */

export const newCode = async ({ tid, code, custom, digits }) => {
  // 规则表取出规则
  const rules = await models.m_autocode_rules.findAll({
    where: {
      code,
      tenant_id: {
        [Op.in]: [0, tid]
      }
    },
    raw: true
  });

  let rule = rules.find(v => v.tenant_id == tid); // 找出当前租户的规则
  if (!rule) rule = rules.find(v => v.tenant_id == 0); // 当前租户的若无规则则用公用规则

  if (!rule || !rule.status) return '';

  const { prefix, length, key_table, key_field } = rule;

  let currentProfix = prefix.replace(/{{date}}/g, moment().format('YYMMDD')) // 替换短日期
    .replace(/{{longdate}}/g, moment().format('YYYYMMDD')) // 替换长日期
    .replace(/{{tid}}/g, tools.stringToHex(tid)) // 替换租户id，转成十六进制
    .replace(/{{custom}}/g, custom || ''); // 替换自定义内容

  // 取租户的最新编码
  const tCode = await models.t_autocodes.findOne({
    where: {
      tenant_id: tid,
      code
    },
    raw: true
  });

  let lastest_code = tCode?.lastest_code;
  let autoCode = '', index;
  while (1) {
    index = 1;
    lastest_code = lastest_code || {};
    if (lastest_code[currentProfix]) { // 当前有序号
      index = Number(lastest_code[currentProfix]) + 1; // 序号递增
    }
    const lengthRequire = tools.isNumber(digits) ? Number(digits) : length; // 流水号长度要求

    if (String(index).length >= lengthRequire) { // 序号超出要求，按正常值
      index = `${index}`;
    } else {
      index = (Array(lengthRequire).join('0') + String(index)).slice(-lengthRequire); // 长度不够0来凑
    }
    lastest_code[currentProfix] = index;

    autoCode = `${currentProfix}${index}`;
    // 查询该编码是否重复
    const cnt = await models[key_table].count({
      where: {
        [key_field]: autoCode,
        tenant_id: tid
      }
    });
    // 若没重复，则退出循环；若有重复，则继续计算下一编码
    if (cnt < 1) {
      break;
    }
  }
  // 纯数字的路径，需要用双引号
  if (tools.isNumber(currentProfix)) {
    currentProfix = `"${currentProfix}"`;
  }

  // 记录最新编码
  if (tCode) {
    await models.t_autocodes.update({ lastest_code: Sequelize.literal(`JSON_SET(IFNULL(lastest_code, JSON_OBJECT()), '$.${currentProfix}', '${index}')`) }, {
      where: { tenant_id: tid, code }
    });
  } else {
    await models.t_autocodes.create({
      tenant_id: tid,
      code,
      lastest_code: { [currentProfix]: index }
    });
  }

  return autoCode;
};

/**
 * 检查是否有重复编码
 * @param {string} tid 租户id
 * @param {string} code 代码
 * @param {array} fieldValue 键值对 {field1: value1, field2: value2 ...}
 * @param {array} exclude 排除在外的键值对 [field,value]
 * */
export const checkRepeat = async (tid, code, fieldValue, exclude) => {
  // 规则表取出规则
  const rules = await models.m_autocode_rules.findAll({
    where: {
      code,
      tenant_id: {
        [Op.in]: [0, tid]
      }
    },
    raw: true
  });

  let rule = rules.find(v => v.tenant_id == tid); // 找出当前租户的规则
  if (!rule) rule = rules.find(v => v.tenant_id == 0); // 当前租户的若无规则则用公用规则

  if (!rule || !rule.unique_field || rule.unique_field.length < 1) return '';

  const { unique_field, key_table } = rule;

  const excludeWhere = exclude ? [{ [exclude[0]]: { [Op.ne]: exclude[1] } }] : [];
  // unique_field,多个字段组合查重，字段间用逗号分割
  const repeatArr = [];
  for (const field of unique_field) {
    const subField = field.split(',').filter(v => fieldValue[v] !== undefined);
    if (subField.length > 0) {
      const opAnd = [...subField.map(v => ({ [v]: fieldValue[v] })), excludeWhere];
      if (tid) {
        opAnd.push({ tenant_id: tid });
      }
      const cnt = await models[key_table].count({
        where: {
          [Op.and]: opAnd
        }
      });
      repeatArr.push(cnt);
    }
  }
  return repeatArr.length > 0 ? repeatArr.reduce((a, b) => a + b) > 0 : false;
}

export default { newCode, checkRepeat };
